package util;

import static java.lang.System.nanoTime;

/**
 * For testing / debug purposes.
 * 
 * <pre>
 *  private Stopwatch stopwatch = new Stopwatch();
 *  ...
 *  public void method1() {
 *      stopwatch.reset();
 *      for (...) {
 *          ...
 *          stopwatch.start();
 *          operation1();
 *          stopwatch.stop();
 *          ...
 *      }
 *      System.out.println("operation 1 max timing is " + stopwatch.getMaxLapTime());
 *  }
 *  ...
 *  public void method2() {
 *      stopwatch.reset();
 *      for (...) {
 *          ...
 *          stopwatch.start();
 *          operation2();
 *          stopwatch.stop();
 *          ...
 *      }
 *      System.out.println("operation 2 max timing is " + stopwatch.getMaxLapTime());
 *  }
 * </pre>
 * 
 * @author Mykhaylo Adamovych
 */
public class Stopwatch {
    protected long totalTime;
    protected long maxLapTime;
    protected long minLapTime;
    protected long lapsCount;
    protected long lastThreshold;
    
    /**
     * Human readable time in seconds
     * 
     * @param nanoTime
     * @return time in seconds
     */
    public static final String toSeconds(long nanoTime) {
        return String.format("%.9f", nanoTime / 1000000000.0);
    }
    
    public long getAverageLapTime() {
        if (lapsCount == 0)
            return 0;
        return totalTime / lapsCount;
    }
    
    public long getMaxLapTime() {
        return maxLapTime;
    }
    
    public long getMinLapTime() {
        return minLapTime;
    }
    
    public long getTotalTime() {
        return totalTime;
    }
    
    /**
     * Returns last lap time, process statistic.
     */
    public long lapTime() {
        return processLapTime();
    }
    
    private long processLapTime() {
        if (lastThreshold == 0)
            throw new IllegalStateException("Stopwatch is stopped.");
        final long now = nanoTime();
        final long lapTime = now - lastThreshold;
        lapsCount++;
        totalTime += lapTime;
        if (lapTime > maxLapTime)
            maxLapTime = lapTime;
        if (lapTime < minLapTime)
            minLapTime = lapTime;
        lastThreshold = nanoTime();
        return lapTime;
    }
    
    /**
     * Resets statistic and starts.
     */
    public void reset() {
        totalTime = 0;
        maxLapTime = 0;
        minLapTime = 0;
        lapsCount = 0;
        start();
    }
    
    /**
     * Starts time watching.
     */
    public void start() {
        lastThreshold = nanoTime();
    }
    
    /**
     * Suspends time watching, returns last lap time.
     */
    public long stop() {
        final long lapTime = processLapTime();
        lastThreshold = 0;
        return lapTime;
    }
}
